package com.mc.fastkit.ext

import android.app.Activity
import android.graphics.Bitmap
import android.graphics.Point
import android.graphics.Rect
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.ViewTreeObserver
import android.view.animation.AnimationUtils
import android.widget.FrameLayout
import android.widget.LinearLayout
import android.widget.RelativeLayout
import androidx.annotation.AnimRes
import androidx.annotation.LayoutRes
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.drawToBitmap
import androidx.core.view.isGone
import androidx.core.view.isInvisible
import androidx.core.view.isVisible
import androidx.core.view.marginBottom
import androidx.core.view.marginEnd
import androidx.core.view.marginStart
import androidx.core.view.marginTop
import androidx.core.view.setMargins
import com.mc.fastkit.callback.OnSingleClickListener
import com.mc.fastkit.utils.KeyboardUtils

val View.activity: Activity?
    get() = context.activity

val View.linearLayoutParams: LinearLayout.LayoutParams
    get() {
        return layoutParams.cast()
    }

val View.frameLayoutParams: FrameLayout.LayoutParams
    get() {
        return layoutParams.cast()
    }

val View.relativeLayoutParams: RelativeLayout.LayoutParams
    get() {
        return layoutParams.cast()
    }

val View.constraintLayoutParams: ConstraintLayout.LayoutParams
    get() {
        return layoutParams.cast()
    }

fun View.runOnUiThread(runnable: () -> Unit) {
    context.activity!!.runOnUiThread(runnable)
}

fun View.singleClick(listener: ((View) -> Unit)?) {
    setOnSingleClickListener(500, listener)
}

fun View.singleClick2(listener: ((View, isFast: Boolean) -> Unit)?) {
    setOnSingleClickListener2(500, listener)
}

fun View.singleClick(delay: Long, listener: ((View) -> Unit)?) {
    setOnSingleClickListener(delay, listener)
}

fun View.singleClick2(delay: Long, listener: ((View, isFast: Boolean) -> Unit)?) {
    setOnSingleClickListener2(delay, listener)
}

fun View.setOnSingleClickListener(delay: Long = 500, listener: ((View) -> Unit)?) {
    if (listener == null) {
        setOnClickListener(null)
        return
    }
    setOnClickListener(object : OnSingleClickListener(delay) {
        override fun onSingleClick(view: View, isFast: Boolean) {
            if (!isFast) {
                listener.invoke(view)
            }
        }
    })
}

fun View.setOnSingleClickListener2(
    delay: Long = 500,
    listener: ((View, isFast: Boolean) -> Unit)?
) {
    if (listener == null) {
        setOnClickListener(null)
        return
    }
    setOnClickListener(object : OnSingleClickListener(delay) {
        override fun onSingleClick(view: View, isFast: Boolean) {
            listener.invoke(view, isFast)
        }
    })
}

fun View.gone() = run { isGone = true }

fun View.visible() = run { isVisible = true }

fun View.invisible() = run { isInvisible = true }

inline fun View.visibleIf(crossinline predicate: () -> Boolean) = apply {
    if (!isVisible && predicate()) isVisible = true
}

inline fun View.visibleOrGone(crossinline predicate: () -> Boolean) = apply {
    isVisible = predicate()
}

inline fun View.visibleOrInvisible(crossinline predicate: () -> Boolean) = apply {
    if (predicate()) isVisible = true
    else isInvisible = true
}

fun View.showKeyboard(flags: Int = 0) = KeyboardUtils.showKeyboard(this, flags)

fun View.hideKeyboard() = KeyboardUtils.hideKeyboard(this)

inline fun <T : View> T.afterMeasured(crossinline predicate: () -> Unit) {
    viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
        override fun onGlobalLayout() {
            if (measuredWidth > 0 && measuredHeight > 0) {
                viewTreeObserver.removeOnGlobalLayoutListener(this)
                predicate.invoke()
            }
        }
    })
}

fun View.setWidth(width: Int) {
    var lp = layoutParams
    if (lp == null) {
        lp = ViewGroup.LayoutParams(width, -2)
    } else {
        lp.width = width
    }
    layoutParams = lp
}

fun View.setHeight(height: Int) {
    var lp = layoutParams
    if (lp == null) {
        lp = ViewGroup.LayoutParams(-2, height)
    } else {
        lp.height = height
    }
    layoutParams = lp
}

fun View.setSize(width: Int, height: Int) {
    var lp = layoutParams
    if (lp == null) {
        lp = ViewGroup.LayoutParams(width, height)
    } else {
        lp.width = width
        lp.height = height
    }
    layoutParams = lp
}

fun View.getLocalVisibleRect(): Rect {
    val rect = Rect()
    getLocalVisibleRect(rect)
    return rect
}

fun View.getGlobalVisibleRect(): Rect {
    val rect = Rect()
    getGlobalVisibleRect(rect)
    return rect
}

fun View.getLocationOnScreen(): Point {
    val location = IntArray(2)
    getLocationOnScreen(location)
    return Point(location[0], location[1])
}

fun View.getLocationInWindow(): Point {
    val location = IntArray(2)
    getLocationInWindow(location)
    return Point(location[0], location[1])
}

fun View.setPaddingStart(paddingStart: Int) {
    setPaddingRelative(paddingStart, paddingTop, paddingRight, paddingBottom)
}

fun View.setPaddingTop(paddingTop: Int) {
    setPaddingRelative(paddingLeft, paddingTop, paddingRight, paddingBottom)
}

fun View.setPaddingEnd(paddingEnd: Int) {
    setPaddingRelative(paddingLeft, paddingTop, paddingEnd, paddingBottom)
}

fun View.setPaddingBottom(paddingBottom: Int) {
    setPaddingRelative(paddingLeft, paddingTop, paddingRight, paddingBottom)
}

fun View.setPaddingHorizontal(padding: Int) {
    setPaddingRelative(padding, paddingTop, padding, paddingBottom)
}

fun View.setPaddingVertical(padding: Int) {
    setPaddingRelative(paddingStart, padding, paddingEnd, padding)
}

fun View.setMargins(margins: Int) {
    val lp = layoutParams as ViewGroup.MarginLayoutParams
    lp.setMargins(margins)
    layoutParams = lp
}

fun View.setStartMargin(margin: Int) {
    val lp = layoutParams as ViewGroup.MarginLayoutParams
    lp.setMargins(margin, marginTop, marginEnd, marginBottom)
    layoutParams = lp
}

fun View.setTopMargin(margin: Int) {
    val lp = layoutParams as ViewGroup.MarginLayoutParams
    lp.setMargins(marginStart, margin, marginEnd, marginBottom)
    layoutParams = lp
}

fun View.setEndMargin(margin: Int) {
    val lp = layoutParams as ViewGroup.MarginLayoutParams
    lp.setMargins(marginStart, marginTop, margin, marginBottom)
    layoutParams = lp
}

fun View.setBottomMargin(margin: Int) {
    val lp = layoutParams as ViewGroup.MarginLayoutParams
    lp.setMargins(marginStart, marginTop, marginEnd, margin)
    layoutParams = lp
}

fun View.setMarginHorizontal(margin: Int) {
    val lp = layoutParams as ViewGroup.MarginLayoutParams
    lp.setMargins(margin, marginTop, margin, marginBottom)
    layoutParams = lp
}

fun View.setMarginVertical(margin: Int) {
    val lp = layoutParams as ViewGroup.MarginLayoutParams
    lp.setMargins(marginStart, margin, marginEnd, margin)
    layoutParams = lp
}

fun View.startAnimation(@AnimRes animRes: Int) {
    startAnimation(AnimationUtils.loadAnimation(context, animRes))
}

fun ViewGroup.inflater(
    @LayoutRes layoutId: Int, root: ViewGroup = this, attachToRoot: Boolean = false
): View {
    return LayoutInflater.from(context).inflate(layoutId, root, attachToRoot)
}

fun View.toBitmap(config: Bitmap.Config = Bitmap.Config.ARGB_8888): Bitmap {
    if (width == 0 || height == 0) {
        measure(
            View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
            View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
        )
        layout(0, 0, measuredWidth, measuredHeight)
    }
    return drawToBitmap(config)
}